home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
FishMarket 1.0
/
FishMarket v1.0.iso
/
fishies
/
526-550
/
disk_540
/
browser
/
browserii_src.lzh
/
Actions.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-07-29
|
18KB
|
673 lines
/*
* Actions.c - Copyright © 1991 by S.R. & P.C.
*
* Created: 02 Mar 1991 15:50:36
* Modified: 29 Jul 1991 07:10:23
*
* Make>> make
*/
#include "Global.h"
#include "DosVar.h"
#include "FileList.h"
#include "ActionBack.h"
#include "Process.h"
#include "proto/Actions.h"
#include "proto/Copy.h"
#include "proto/ActionBack.h"
#include "proto/Request.h"
#include "proto/File.h"
#include "proto/FileList.h"
extern void setmem(void *mem, size_t size, long value);
extern struct ExecBase *SysBase;
extern char *ReqTitle;
/* just request cmd can't be done on volumes/devices/assigns */
static void TellNoVolumes(char *cmd)
{
SimpleRequest(ReqTitle, "Can't %s volumes.", cmd);
}
/* Get the only element of list */
static struct SuperFileInfo *GetSelected(struct HeadFileList *hfl)
{
struct BrowserDir *bd;
bd = (struct BrowserDir *)hfl->DirList.mlh_Head;
return (struct SuperFileInfo *)bd->SuperFileList.mlh_Head;
}
/* Tell if str has a single star in it. if yes, return a pointer to it */
static char *has_star(char *str)
{
char *s;
while(*str && *str != '*') str++;
if (!*str)
return NULL; /* no '*' in str */
else
s = str++; /* '*' found so keep pointer and skip it */
while(*str && *str != '*') str++;
/* now, if *str != '\0', another star was found, so return NULL */
return (*str) ? NULL : s;
}
/*
* Check for difference between the two names to make sure rename/duplicate
* can be done. The new name mustn't be a single star, that is to say "*".
* If the old one have a star '*' in it, the new one MUST have one too and
* only one. And if the old name has no star, the two names must be different.
* If ok, then preparse new name as a format for SPrintf().
*/
static BOOL ValidRenDup(char *NewName, char *OldName)
{
char buf[32];
char *s;
if (!(*NewName) || !strcmp(NewName, "*") || !strcmp(NewName, OldName))
return FALSE;
if (has_star(OldName)) {
if (!(s = has_star(NewName))) {
SimpleRequest(ReqTitle, "You MUST keep a single '*' in name.");
return FALSE;
}
else {
strcpy(buf, s+1); /* save prefix in buf */
strcpy(s, "%s"); /* replace '*' with "%s" */
strcpy(s+2, buf); /* restore prefix */
}
}
return TRUE;
}
/* Build new name with name and pattern given by Init rename/duplicate */
short MakeNewName(char *NewName, char *fmt, char *OldName)
{
char buffer[64];
if (SPrintf(buffer, fmt, OldName) > 30) {
/* multiply result by 2 because "Skip" take place of usual "Retry" in
* requester and no retry is provided here. */
return ThreeGadRequest("Skip", NULL, "Filename to long: \"%s\"", buffer) << 1;
}
else {
/* give back newname only if no trouble */
strcpy(NewName, buffer);
return A_RETRY;
}
}
static BOOL InitRename(struct HeadFileList *hfl)
{
struct SuperFileInfo *sfi;
BPTR VolumeLock;
char *Title, *NewName, *s;
char tmpbuf[32];
short Ok = A_RETRY;
if (hfl->Vols > 1 || hfl->Vols && hfl->Vols < hfl->NumEntries) {
SimpleRequest(ReqTitle, "Can't relabel multiple volumes.");
return FALSE;
}
if (hfl->NumEntries > 1 || (hfl->Select.si_Flags & SI_AFFECT_SUBDIRS)) {
strcpy(tmpbuf, "*");
Title = "Add suffix and/or prefix...";
}
else if (hfl->NumEntries == 1) {
Title = "Enter new name...";
sfi = GetSelected(hfl);
strcpy(tmpbuf, sfi->FileInfo.fi_Name);
switch(sfi->FileInfo.fi_Type) {
case DLX_ASSIGN:
SimpleRequest(ReqTitle, "Can't rename an assign.");
return FALSE;
case DLX_DEVICE: /* for a device, obtain mounted volume name, and continue to volume handling routine */
while(Ok == A_RETRY && !(VolumeLock = Lock(tmpbuf, ACCESS_READ)))
Ok = ThreeGadRequest("Retry", NULL, "Couldn't access \"%s\"\n%s.", tmpbuf, StrIoErr());
if (Ok != A_RETRY)
return FALSE;
PathName(VolumeLock, tmpbuf, 31);
UnLock(VolumeLock);
case DLX_VOLUME: /* for a volume, remove ending ':' */
case DLX_UNMOUNTED:
s = &tmpbuf[strlen(tmpbuf)-1];
if (*s == ':') *s = '\0';
break;
}
}
else
return FALSE;
NewName = hfl->ActionArgs.NewName;
strcpy(NewName, tmpbuf);
if (GetString(NewName, Title, NULL, 38, 31) && ValidRenDup(NewName, tmpbuf))
return TRUE;
else
return FALSE;
}
static BOOL InitTouch(struct HeadFileList *hfl)
{
if (hfl->Vols) {
TellNoVolumes("touch");
return FALSE;
}
DateStamp(&hfl->ActionArgs.DateStamp);
return TRUE;
}
static BOOL InitSetComment(struct HeadFileList *hfl)
{
char buf[82];
char *s;
if (hfl->Vols) {
TellNoVolumes("comment");
return FALSE;
}
if (hfl->NumEntries == 0)
return FALSE;
buf[0] = '\0';
if (hfl->NumEntries == 1 && (s = GetSelected(hfl)->FileInfo.fi_Comment))
strcpy(buf, s);
if (GetString(buf, "Set Comment...", NULL, 50, 80)) {
strcpy(hfl->ActionArgs.Comment, buf);
return TRUE;
}
return FALSE;
}
static BOOL InitSetProtect(struct HeadFileList *hfl)
{
struct SelectInfo SelectInfo;
if (hfl->Vols) {
TellNoVolumes("protect");
return FALSE;
}
if (hfl->NumEntries == 0)
return FALSE;
else if (hfl->NumEntries == 1 && !(hfl->Select.si_Flags & SI_AFFECT_SUBDIRS))
SelectInfo.si_PosProtect = GetSelected(hfl)->FileInfo.fi_Protection;
else
SelectInfo.si_PosProtect = 0x0F; /* four lower bits (rwed) */
SelectInfo.si_NegProtect = 0;
if (FiltersReq(&SelectInfo, PROTECT_REQ)) {
hfl->ActionArgs.Protection.Pos = SelectInfo.si_PosProtect;
hfl->ActionArgs.Protection.Neg = SelectInfo.si_NegProtect;
return TRUE;
}
return FALSE;
}
static BOOL InitDelete(struct HeadFileList *hfl)
{
char *MiddleText = NULL;
short Flags;
if (hfl->Vols) {
TellNoVolumes("delete");
return FALSE;
}
if (hfl->NumEntries == 0)
return FALSE;
Flags = hfl->Select.si_Flags;
/* Don't ask for Delete All if AFFECT_SUBDIRS and DIRS isn't selected */
if (hfl->Dirs)
MiddleText = "Delete All";
switch(ThreeGadRequest("Delete", MiddleText, "Really delete all marked files ?")) {
case 0: /* CANCEL */
return FALSE;
case 1: /* DELETE */
/* Delete files and non-empty dirs */
break;
case 2: /* DELETE ALL */
if (!(hfl->Select.si_Flags & SI_AFFECT_SUBDIRS))
hfl->Select.si_Flags = SI_AFFECT_SUBDIRS|SI_ALL_FILES|SI_ALL_DIRS;
}
return TRUE;
}
static BOOL InitAndDoDuplicate(struct HeadFileList *hfl)
{
char tmpbuf[40];
char *Title, *NewName;
NewName = hfl->ActionArgs.NewName;
if (hfl->Vols) {
TellNoVolumes("duplicate");
return FALSE;
}
if (hfl->NumEntries > 1 || (hfl->Select.si_Flags & SI_AFFECT_SUBDIRS)) {
strcpy(tmpbuf, "*");
Title = "Add suffix and/or prefix...";
}
else if (hfl->NumEntries == 1) {
strcpy(tmpbuf, GetSelected(hfl)->FileInfo.fi_Name);
Title = "Duplicate...";
}
else
return FALSE;
strcpy(NewName, tmpbuf);
if (GetString(NewName, Title, NULL, 38, 31) && ValidRenDup(NewName, tmpbuf)) {
if (BaseName(NewName) == NewName) {
hfl->CopyMode = (hfl->CopyMode & ~(CM_ALLWAYS_MOVE|CM_CONTEXT)) | CM_ALLWAYS_COPY; /* Tell CopyMove() to copy ! */
CopyMove(hfl);
}
else
SimpleRequest(ReqTitle, "Full path name not allowed for Duplicate.");
}
return FALSE; /* Allways return FALSE since the action is done in InitAction */
}
static short MakeDir(struct HeadFileList *hfl, char *Name)
{
struct SuperFileInfo sfi;
struct FileInfoBlock *fib;
BPTR NewDir;
short Ok = A_RETRY;
if (!(fib = AllocMem(sizeof(struct FileInfoBlock), MEMF_PUBLIC|MEMF_CLEAR)))
return FALSE;
setmem(&sfi, sizeof(struct SuperFileInfo), 0);
/* Prevent CreateDir() bug which create a dir even if a file with the same name already exists */
while(Ok == A_RETRY && (NewDir = Lock(Name, ACCESS_READ))) {
UnLock(NewDir);
Ok = ThreeGadRequest("Retry", "Skip", "Couldn't create dir \"%s\"\n%s.", Name, "Object already exists");
}
while(Ok == A_RETRY && !(NewDir = CreateDir(Name)))
Ok = ThreeGadRequest("Retry", "Skip", "Couldn't create dir \"%s\"\n%s.", Name, StrIoErr());
if (Ok == A_RETRY) {
UnLock(NewDir);
if (Name == BaseName(Name) && (Ok = GetFib(Name, fib, TRUE)) == A_RETRY) {
Fib2Fi(&sfi.FileInfo, fib);
strcpy(sfi.OldName, sfi.FileInfo.fi_Name);
sfi.ActionBack |= AB_NEW_ENTRY;
SendActionBack(&sfi, NULL, hfl->DestDir);
}
}
FreeMem(fib, sizeof(struct FileInfoBlock));
return Ok;
}
#define MAKEDIR_BUFSIZE 46
static BOOL InitAndDoMakeDir(struct HeadFileList *hfl)
{
BPTR CD;
char *s, *dir, c;
char Buffer[MAKEDIR_BUFSIZE];
BOOL quote;
short Ok = A_RETRY;
if (!hfl->DestDir) { /* this is the main window */
SimpleRequest(ReqTitle, "Can't create a dir in this window.");
return FALSE;
}
setmem(Buffer, MAKEDIR_BUFSIZE, 0);
if (GetString(Buffer, "Makedir(s)...", NULL, MAKEDIR_BUFSIZE-1, MAKEDIR_BUFSIZE-1)) {
CD = CurrentDir(hfl->DestDir);
s = Buffer;
while (Ok != A_STOP && *s) {
while ((c = *s) && (c == ' ' || c == '\t'))
s++; /* skip leading spaces */
if (!c)
break;
if (c == '"') {
quote = TRUE;
s++;
}
else
quote = FALSE;
dir = s;
while((c = *s) && ((quote && c != '"') || (!quote && c != ' ')))
s++;
*s++ = '\0';
Ok = MakeDir(hfl, dir);
}
SendUpdateDir(hfl->DestDir);
CurrentDir(CD);
}
return FALSE; /* Allways return FALSE since action is done in init */
}
static short DoRelabel(char *Dev, char *Name)
{
long args[7];
char *str;
struct MsgPort *task;
short Ok = A_RETRY;
while(Ok == A_RETRY && !(task = (struct MsgPort *)DeviceProc(Dev)))
Ok = ThreeGadRequest("Retry", NULL, "Couldn't access \"%s\"\n%s.", Dev, StrIoErr());
if (Ok == A_RETRY) {
str = AllocMem(65L, MEMF_PUBLIC);
CtoBStr(Name, (ULONG)str>>2, 64);
args[0] = (ULONG)str>>2;
while (Ok == A_RETRY && !SendPacket(ACTION_RENAME_DISK, args, task))
Ok = ThreeGadRequest("Retry", NULL, "Couldn't relabel \"%s\"\n%s.", Name, StrIoErr());
FreeMem(str, 65L);
if (Ok == A_RETRY) {
args[0] = 1;
SendPacket(ACTION_INHIBIT, args, task);
args[0] = 0;
SendPacket(ACTION_INHIBIT, args, task);
}
}
return Ok;
}
static short DoRename(struct SuperFileInfo *sfi, union ActionArgs *Args)
{
short Ok = A_RETRY;
char *OldName, *NewName;
OldName = sfi->OldName;
NewName = sfi->FileInfo.fi_Name;
switch(sfi->FileInfo.fi_Type) {
case DLX_DIR:
case DLX_FILE:
if ((Ok = MakeNewName(NewName, Args->NewName, OldName)) == A_RETRY) {
while(Ok == A_RETRY && !Rename(OldName, NewName))
Ok = ThreeGadRequest("Retry", "Skip", "Couldn't rename \"%s\" as \"%s\"\n%s.", OldName, NewName, StrIoErr());
if (Ok == A_RETRY) {
/* if newname hasn't the same directory path, just remove old file from window, else, update string */
if (NewName == BaseName(NewName))
sfi->ActionBack |= AB_RENAME_ENTRY;
else
sfi->ActionBack |= AB_DELETE_SOURCE;
}
}
break;
case DLX_DEVICE:
case DLX_VOLUME:
if ((Ok = DoRelabel(OldName, Args->NewName)) == A_RETRY)
sfi->ActionBack |= AB_SCANDEVS;
break;
}
return Ok;
}
short Touch(char *Name, struct DateStamp *ds)
{
struct MsgPort *task;
long args[7];
char *str;
struct Process *pp;
short Ok = A_RETRY;
pp = (struct Process *)SysBase->ThisTask;
while(Ok == A_RETRY && !(task = (struct MsgPort *)DeviceProc(Name)))
Ok = ThreeGadRequest("Retry", "Skip", "Couldn't access \"%s\"\n%s.", Name, StrIoErr());
if (Ok == A_RETRY) {
str = AllocMem(65, MEMF_PUBLIC);
CtoBStr(Name, (BSTR)str>>2L, 64);
args[1] = pp->pr_CurrentDir;
args[2] = (BSTR)str>>2L;
args[3] = (long)ds;
while (Ok == A_RETRY && !SendPacket(ACTION_SET_DATE, args, task))
Ok = ThreeGadRequest("Retry", "Skip", "Couldn't touch \"%s\"\n%s.", Name, StrIoErr());
FreeMem(str, 65);
}
return Ok;
}
static short DoTouch(struct SuperFileInfo *sfi, union ActionArgs *Args)
{
short Ok;
if ((Ok = Touch(sfi->FileInfo.fi_Name, &Args->DateStamp)) == A_RETRY) {
sfi->FileInfo.fi_Date = Args->DateStamp;
sfi->ActionBack |= AB_UPDATE_STRING;
}
return Ok;
}
short Comment(char *Name, char *FileNote)
{
short Ok = A_RETRY;
while (Ok == A_RETRY && !SetComment(Name, FileNote))
Ok = ThreeGadRequest("Retry", "Skip", "Couldn't set comment of \"%s\"\n%s.", Name, StrIoErr());
return Ok;
}
static short DoSetComment(struct SuperFileInfo *sfi, union ActionArgs *Args)
{
short Ok = A_RETRY;
if (Ok = Comment(sfi->FileInfo.fi_Name, Args->Comment)) {
CleanFileInfo(&sfi->FileInfo);
if (strlen(Args->Comment)) {
sfi->FileInfo.fi_Comment = CopyStr(Args->Comment);
sfi->FileInfo.fi_Protection |= FIBF_COMMENT;
}
else
sfi->FileInfo.fi_Protection &= ~FIBF_COMMENT;
sfi->ActionBack |= AB_UPDATE_STRING;
}
return Ok;
}
short Protect(char *Name, long Protection)
{
short Ok = A_RETRY;
Protection = (Protection & 0x00FF) ^ 0x0F; /* clear comment bit and complement four lower bits. strange AmigaDOS !! */
while (Ok == A_RETRY && !SetProtection(Name, Protection))
Ok = ThreeGadRequest("Retry", "Skip", "Couldn't protect \"%s\"\n%s.", Name, StrIoErr());
return Ok;
}
static short DoSetProtect(struct SuperFileInfo *sfi, union ActionArgs *Args)
{
long Protection;
short Ok = A_RETRY;
if (Args->Protection.Neg & FIBF_COMMENT) { /* Protect -c "file" means remove comment */
if ((Ok = Comment(sfi->FileInfo.fi_Name, "")) == A_RETRY)
CleanFileInfo(&sfi->FileInfo);
}
Protection = (sfi->FileInfo.fi_Protection | Args->Protection.Pos) & ~Args->Protection.Neg;
if (Ok == A_RETRY && (Ok = Protect(sfi->FileInfo.fi_Name, Protection))) {
sfi->FileInfo.fi_Protection = Protection;
sfi->ActionBack |= AB_UPDATE_STRING;
}
return Ok;
}
/*
* Don't request for a directory not empty since user may already
* has answered after a file couldn't be deleted in this dir.
*/
static short DoDelete(struct SuperFileInfo *sfi)
{
char *Name;
short err=0, Ok = A_RETRY;
Name = sfi->FileInfo.fi_Name;
while (Ok == A_RETRY && !DeleteFile(Name) && (err = IoErr()) != ERROR_DIRECTORY_NOT_EMPTY) {
Ok = ThreeGadRequest("Retry", "Skip", "Couldn't delete \"%s\"\n%s.", Name, DosError(err));
err = 0;
}
if (Ok == A_RETRY && err == 0)
sfi->ActionBack |= AB_DELETE_SOURCE;
return Ok;
}
static short DoRecurse(struct HeadFileList *hfl, struct SuperFileInfo *StartSFI, struct FileInfoBlock *StartFib, short (*Action)(struct SuperFileInfo *, union ActionArgs *))
{
struct SuperFileInfo *sfi;
struct FileInfoBlock *OldFib, *fib;
struct SelectInfo *Select;
char *DirName;
BPTR DirLock, CD;
short err = 0, Ok = A_RETRY;
long next;
fib = AllocMem(sizeof(struct FileInfoBlock), MEMF_PUBLIC|MEMF_CLEAR);
OldFib = AllocMem(sizeof(struct FileInfoBlock), MEMF_PUBLIC|MEMF_CLEAR);
sfi = AllocMem(sizeof(struct SuperFileInfo), MEMF_PUBLIC|MEMF_CLEAR);
if (fib && OldFib && sfi) {
Select = &hfl->Select;
DirName = StartFib->fib_FileName;
while(Ok == A_RETRY && !(DirLock = Lock(DirName, ACCESS_READ)))
Ok = ThreeGadRequest("Retry", "Skip", "Couldn't access \"%s\"\n%s.", DirName, StrIoErr());
if (Ok == A_RETRY && DirLock) {
CD = CurrentDir(DirLock);
*fib = *StartFib;
if (!(next = ExNext(DirLock, fib)) && (err = IoErr()) != ERROR_NO_MORE_ENTRIES)
Ok = ThreeGadRequest("Skip", NULL, "Error reading directory \"%s\"\n%s.", DirName, DosError(err)) << 1;
if (Ok == A_RETRY) {
while(Ok != A_STOP && next) {
*OldFib = *fib;
Fib2Fi(&sfi->FileInfo, fib);
/* Examine next entry before possible delete (need for Commodore RAM disk) */
next = ExNext(DirLock, fib);
err = IoErr();
strcpy(sfi->OldName, sfi->FileInfo.fi_Name); /* save name for actions which change it */
switch(sfi->FileInfo.fi_Type) {
case DLX_FILE:
if (MatchFilters(&sfi->FileInfo, Select))
Ok = Action(sfi, &hfl->ActionArgs);
break;
case DLX_DIR:
Ok = DoRecurse(hfl, sfi, OldFib, Action);
}
if (Ok != A_RETRY)
sfi->ActionBack = AB_SELECT;
SendActionBack(sfi, DirLock, NULL);
}
if (Ok == A_RETRY && err != ERROR_NO_MORE_ENTRIES)
Ok = ThreeGadRequest("Skip", NULL, "Error reading directory \"%s\"\n%s.", DirName, DosError(err)) << 1;
CleanFileInfo(&sfi->FileInfo);
}
CurrentDir(CD);
SendUpdateDir(DirLock);
UnLock(DirLock);
}
if (Ok == A_RETRY && MatchFilters(&StartSFI->FileInfo, Select))
Ok = Action(StartSFI, &hfl->ActionArgs);
}
else
Ok = A_STOP;
if (sfi) FreeMem(sfi, sizeof(struct SuperFileInfo));
if (OldFib) FreeMem(OldFib, sizeof(struct FileInfoBlock));
if (fib) FreeMem(fib, sizeof(struct FileInfoBlock));
return Ok;
}
static BOOL (*InitActionArray[])(struct HeadFileList *) = {
InitRename,
InitAndDoMakeDir,
InitAndDoDuplicate,
InitTouch,
InitSetComment,
InitSetProtect,
InitDelete
};
static BOOL (*DoActionArray[])() = {
DoRename,
NULL,
NULL,
DoTouch,
DoSetComment,
DoSetProtect,
DoDelete
};
void DoAction(struct HeadFileList *hfl, short ActionNum)
{
struct BrowserDir *bd;
struct SuperFileInfo *sfi;
struct FileInfoBlock *fib;
short (*Action)(struct SuperFileInfo *, union ActionArgs *);
short Ok = A_RETRY;
if (!(fib = AllocMem(sizeof(struct FileInfoBlock), MEMF_PUBLIC|MEMF_CLEAR)))
return;
Action = DoActionArray[ActionNum];
bd = (struct BrowserDir *)hfl->DirList.mlh_Head;
while( Ok != A_STOP && bd->Node.mln_Succ ) {
if (bd->DirLock)
CurrentDir(bd->DirLock);
sfi = (struct SuperFileInfo *)bd->SuperFileList.mlh_Head;
while(Ok != A_STOP && sfi->Node.mln_Succ) {
/* Examine entry only if necessary */
if (sfi->FileInfo.fi_Type == DLX_DIR && (hfl->Select.si_Flags & SI_AFFECT_SUBDIRS)) {
if ((Ok = GetFib(sfi->FileInfo.fi_Name, fib, TRUE)) == A_RETRY)
Fib2Fi(&sfi->FileInfo, fib);
}
else
Ok = A_RETRY;
if (Ok == A_RETRY) {
switch(sfi->FileInfo.fi_Type) {
case DLX_FILE:
Ok = Action(sfi, &hfl->ActionArgs);
break;
case DLX_DIR:
if (hfl->Select.si_Flags & SI_AFFECT_SUBDIRS)
Ok = DoRecurse(hfl, sfi, fib, Action);
else
Ok = Action(sfi, &hfl->ActionArgs);
break;
default: /* Assign, Device, or Volume */
Ok = Action(sfi, &hfl->ActionArgs);
}
}
if (Ok != A_RETRY)
sfi->ActionBack = AB_SELECT;
SendActionBack(sfi, bd->DirLock, NULL);
sfi = (struct SuperFileInfo *)sfi->Node.mln_Succ;
}
SendUpdateDir(bd->DirLock);
bd = (struct BrowserDir *)bd->Node.mln_Succ;
}
CurrentDir(((struct TaskData *)SysBase->ThisTask->tc_UserData)->td_InitialDir);
FreeMem(fib, sizeof(struct FileInfoBlock));
}
void InitAndDoAction(struct HeadFileList *hfl, short ActionNum)
{
if (InitActionArray[ActionNum](hfl))
DoAction(hfl, ActionNum);
}